home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
aminet
/
comm
/
misc
/
zedzap05.lha
/
utils.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-27
|
34KB
|
973 lines
/* Utils.c: Miscellaneous support routines for xprzmodem.library;
Version 2.10, 12 February 1991, by Rick Huebner.
Released to the Public Domain; do as you like with this code. */
#include <proto/all.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xproto.h"
#include "zmodem.h"
#include "xprzmodem.h"
long OPEN_LIBS = 0; /* the amount of times this library is being */
/* accessed... remeber, the dos.library may */
/* only be closed and opened once, so it is */
/* very important that we know when the last */
/* program finishes accessing the library! */
/* Transfer options to use if XProtocolSetup not called */
struct SetupVars Default_Config = {
NULL, NULL, 0,
{ "C" }, { "N" }, { "16" }, { "0" }, { "10" },
{ "N" }, { "N" }, { "Y" }, { "N" }, { "Y" }, { "0"}, { "8192" },
{ "Y" }, { "N" }, { "Y" }, { "ENV:" }, { "" }
};
#ifdef DEBUGLOG
UBYTE DebugName[] = "Log:XDebug.log";
void *DebugLog = NULL;
#endif
/* Called by comm program to set transfer options */
long __saveds XProtocolSetup(struct XPR_IO *io) {
struct SetupVars *sv, tempsv;
struct xpr_option *option_ptrs[18], *optr, xo_hdr, xo_t, xo_o, xo_b, xo_f;
struct xpr_option xo_e, xo_s, xo_r, xo_a, xo_d, xo_k, xo_p, xo_m, xo_n, xo_c;
struct xpr_option xo_u, xo_v, xo_l;
UBYTE buf[512], *p, *bufback;
long i, len;
/* Allocate memory for transfer options string */
if (!(sv = (void *)io->xpr_data)) {
io->xpr_data = AllocMem((long)sizeof(struct SetupVars),MEMF_CLEAR);
if (!(sv = (void *)io->xpr_data)) {
ioerr(io,"Not enough memory");
return XPRS_FAILURE;
}
/* Start out with default options; merge user changes into defaults */
*sv = Default_Config;
}
/* If options string passed by comm prog, use it; else prompt user */
if (io->xpr_filename)
strcpy(buf,io->xpr_filename);
else {
/* If xpr_options() implemented by comm program, use it */
if (io->xpr_extension >= 1 && io->xpr_options) {
/* Let user edit temp copy of options so we can ignore invalid entries */
/* Have to init all this crud the hard way 'cause it's got to be on the
stack in order to maintain reentrancy */
tempsv = *sv;
xo_hdr.xpro_description = "ZedZap Options:";
xo_hdr.xpro_type = XPRO_HEADER;
xo_hdr.xpro_value = NULL;
xo_hdr.xpro_length = 0;
option_ptrs[0] = &xo_hdr;
xo_t.xpro_description = "Text Mode (Y,N,?,C):";
xo_t.xpro_type = XPRO_STRING;
xo_t.xpro_value = tempsv.option_t;
xo_t.xpro_length = sizeof(tempsv.option_t);
option_ptrs[1] = &xo_t;
xo_o.xpro_description = "Overwrite Mode (Y,N,R,S):";
xo_o.xpro_type = XPRO_STRING;
xo_o.xpro_value = tempsv.option_o;
xo_o.xpro_length = sizeof(tempsv.option_o);
option_ptrs[2] = &xo_o;
xo_b.xpro_description = "I/O Buffer Size (KB):";
xo_b.xpro_type = XPRO_LONG;
xo_b.xpro_value = tempsv.option_b;
xo_b.xpro_length = sizeof(tempsv.option_b);
option_ptrs[3] = &xo_b;
xo_f.xpro_description = "Frame Size (bytes):";
xo_f.xpro_type = XPRO_LONG;
xo_f.xpro_value = tempsv.option_f;
xo_f.xpro_length = sizeof(tempsv.option_f);
option_ptrs[4] = &xo_f;
xo_e.xpro_description = "Error Limit:";
xo_e.xpro_type = XPRO_LONG;
xo_e.xpro_value = tempsv.option_e;
xo_e.xpro_length = sizeof(tempsv.option_e);
option_ptrs[5] = &xo_e;
xo_a.xpro_description = "Auto-Activate Receiver:";
xo_a.xpro_type = XPRO_BOOLEAN;
xo_a.xpro_value = tempsv.option_a;
xo_a.xpro_length = sizeof(tempsv.option_a);
option_ptrs[6] = &xo_a;
xo_d.xpro_description = "Delete After Sending:";
xo_d.xpro_type = XPRO_BOOLEAN;
xo_d.xpro_value = tempsv.option_d;
xo_d.xpro_length = sizeof(tempsv.option_d);
option_ptrs[7] = &xo_d;
xo_k.xpro_description = "Keep Partial Files:";
xo_k.xpro_type = XPRO_BOOLEAN;
xo_k.xpro_value = tempsv.option_k;
xo_k.xpro_length = sizeof(tempsv.option_k);
option_ptrs[8] = &xo_k;
xo_s.xpro_description = "Send Full Path:";
xo_s.xpro_type = XPRO_BOOLEAN;
xo_s.xpro_value = tempsv.option_s;
xo_s.xpro_length = sizeof(tempsv.option_s);
option_ptrs[9] = &xo_s;
xo_r.xpro_description = "Use Received Path:";
xo_r.xpro_type = XPRO_BOOLEAN;
xo_r.xpro_value = tempsv.option_r;
xo_r.xpro_length = sizeof(tempsv.option_r);
option_ptrs[10] = &xo_r;
xo_p.xpro_description = "Default Receive Path:";
xo_p.xpro_type = XPRO_STRING;
xo_p.xpro_value = tempsv.option_p;
xo_p.xpro_length = sizeof(tempsv.option_p);
option_ptrs[11] = &xo_p;
xo_c.xpro_description = "Connect BPS Rate:";
xo_c.xpro_type = XPRO_LONG;
xo_c.xpro_value = tempsv.option_c;
xo_c.xpro_length = sizeof(tempsv.option_c);
option_ptrs[12] = &xo_c;
xo_m.xpro_description = "Maximum Block Size:";
xo_m.xpro_type = XPRO_LONG;
xo_m.xpro_value = tempsv.option_m;
xo_m.xpro_length = sizeof(tempsv.option_m);
option_ptrs[13] = &xo_m;
xo_n.xpro_description = "Send If Files = 0:";
xo_n.xpro_type = XPRO_BOOLEAN;
xo_n.xpro_value = tempsv.option_n;
xo_n.xpro_length = sizeof(tempsv.option_n);
option_ptrs[14] = &xo_n;
xo_l.xpro_description = "Block Change (Y,N,B,F):";
xo_l.xpro_type = XPRO_STRING;
xo_l.xpro_value = tempsv.option_l;
xo_l.xpro_length = sizeof(tempsv.option_l);
option_ptrs[15] = &xo_l;
xo_u.xpro_description = "Open Dos.Library:";
xo_u.xpro_type = XPRO_BOOLEAN;
xo_u.xpro_value = tempsv.option_u;
xo_u.xpro_length = sizeof(tempsv.option_u);
option_ptrs[16] = &xo_u;
xo_v.xpro_description = "ENV-Val Starter:";
xo_v.xpro_type = XPRO_STRING;
xo_v.xpro_value = tempsv.option_v;
xo_v.xpro_length = sizeof(tempsv.option_v);
option_ptrs[17] = &xo_v;
/* Convert Y/N used elsewhere into "yes"/"no" required by spec */
for (i=6; i<=10; ++i) {
optr = option_ptrs[i];
strcpy(optr->xpro_value,(*optr->xpro_value == 'Y') ? "Yes" : "No");
}
optr = option_ptrs[14];
strcpy(optr->xpro_value,(*optr->xpro_value == 'Y') ? "Yes" : "No");
optr = option_ptrs[16];
strcpy(optr->xpro_value,(*optr->xpro_value == 'Y') ? "Yes" : "No");
xpr_options(io,18L,option_ptrs);
/* Convert "yes"/"no" or "on"/"off" into Y/N */
for (i=6; i<=10; ++i) {
optr = option_ptrs[i];
strcpy(optr->xpro_value,(!stricmp(optr->xpro_value,"Yes") || !stricmp(optr->xpro_value,"On")) ? "Y" : "N");
}
optr = option_ptrs[14];
strcpy(optr->xpro_value,(!stricmp(optr->xpro_value,"yes") || !stricmp(optr->xpro_value,"on")) ? "Y" : "N");
optr = option_ptrs[16];
strcpy(optr->xpro_value,(!stricmp(optr->xpro_value,"yes") || !stricmp(optr->xpro_value,"on")) ? "Y" : "N");
/* Convert xpr_options() results into parseable options string */
sprintf(buf,"T%s,O%s,B%s,F%s,E%s,A%s,D%s,K%s,S%s,R%s,C%s,N%s,M%s,L%s,U%s,V%s,P%s",tempsv.option_t,
tempsv.option_o,tempsv.option_b,tempsv.option_f,tempsv.option_e,
tempsv.option_a,tempsv.option_d,tempsv.option_k,tempsv.option_s,
tempsv.option_r,tempsv.option_c,tempsv.option_n,tempsv.option_m,
tempsv.option_l,tempsv.option_u,tempsv.option_v,tempsv.option_p);
/* If xpr_options() not provided, try xpr_gets() instead */
} else {
/* Start buffer with current settings so user can see/edit them in place */
sprintf(buf,"T%s,O%s,B%s,F%s,E%s,A%s,D%s,K%s,S%s,R%s,C%s,N%s,M%s,L%s,U%s,V%s,P%s",sv->option_t,
sv->option_o,sv->option_b,sv->option_f,sv->option_e,
sv->option_a,sv->option_d,sv->option_k,sv->option_s,
sv->option_r,sv->option_c,sv->option_n,sv->option_m,
sv->option_l,sv->option_u,sv->option_v,sv->option_p);
if (io->xpr_gets)
xpr_gets(io,"ZedZap Options:",buf);
}
}
/* Upshift options string for easier parsing */
strupr(buf);
/* Merge new T(ext) option into current settings if given */
/* "TY" = Force Text mode on,
"TN" = Force Text mode off,
"T?" = Use other end's text mode suggestion (default to binary)
"TC" = Ask Comm program for file type */
if (p = find_option(buf,'T')) {
if (*p == 'Y' || *p == 'N' || *p == '?' || *p == 'C') *sv->option_t = *p;
else ioerr(io,"Invalid T Flag Ignored; Should Be Y, N, ?, Or C");
}
/* Merge new O(verwrite) option into current settings if given */
/* "OY" = Yes, delete old file and replace with new one,
"ON" = No, prevent overwrite by appending ".dup" to avoid name collision,
"OR" = Resume transfer at end of existing file,
"OS" = Skip file if it already exists; go on to next */
if (p = find_option(buf,'O')) {
if (*p == 'R' && !io->xpr_finfo) ioerr(io,"Can't Resume; xpr_finfo() not supported");
else if (*p == 'Y' || *p == 'N' || *p == 'R' || *p == 'S') *sv->option_o = *p;
else ioerr(io,"Invalid O Flag Ignored; Should Be Y, N, R, Or S");
}
/* Merge new B(uffer) setting into current settings if given */
/* Size of file I/O buffer in kilobytes */
if (p = find_option(buf,'B')) {
len = atol(p);
if (len < 1) len = 1;
sprintf(sv->option_b,"%ld",len);
}
/* Merge new F(ramelength) setting into other settings if given */
/* Number of bytes we're willing to send or receive between ACKs.
0 = unlimited; nonstop streaming data */
if (p = find_option(buf,'F')) {
len = atol(p);
if (len < 0) len = 0;
if (len > 0 && len < MINBLOCK) len = MINBLOCK;
sprintf(sv->option_f,"%ld",len);
}
/* Merge new E(rror limit) setting into other settings if given */
/* Number of sequential errors which will cause an abort */
if (p = find_option(buf,'E')) {
len = atol(p);
if (len < 1)
len = 1;
if (len > 32767)
len = 32767;
sprintf(sv->option_e,"%ld",len);
}
/* Merge new A(uto-activate) setting into other settings if given */
/* "AY" = Automatically call XProtocolReceive() if ZRQINIT string received
"AN" = Don't look for ZRQINIT; user will explicitly activate receive */
if (p = find_option(buf,'A')) {
if (*p == 'Y' || *p == 'N') *sv->option_a = *p;
else ioerr(io,"Invalid A Flag Ignored; Should Be Y Or N");
}
/* Merge new D(elete after sending) setting into other options */
/* "DY" = Delete files after successfully sending them
"DN" = Don't delete files after sending */
if (p = find_option(buf,'D')) {
if (*p == 'Y' && (io->xpr_extension < 2 || !io->xpr_unlink))
ioerr(io,"Can't use DY; xpr_unlink() not supported");
else if (*p == 'Y' || *p == 'N') *sv->option_d = *p;
else ioerr(io,"Invalid D Flag Ignored; Should Be Y Or N");
}
/* Merge new K(eep partial files) setting into other options */
/* "KY" = Keep partially-received file fragments to allow later resumption
"KN" = Delete partially-received file fragments */
if (p = find_option(buf,'K')) {
if (*p == 'N' && (io->xpr_extension < 2 || !io->xpr_unlink))
ioerr(io,"Can't use KN; xpr_unlink() not supported");
else if (*p == 'Y' || *p == 'N') *sv->option_k = *p;
else ioerr(io,"Invalid K Flag Ignored; Should Be Y Or N");
}
/* Merge new S(end full path) setting into other options */
/* "SY" = Send full filename including directory path to receiver
"SN" = Send only simple filename portion, not including directory path */
if (p = find_option(buf,'S')) {
if (*p == 'Y' || *p == 'N') *sv->option_s = *p;
else ioerr(io,"Invalid S Flag Ignored; Should Be Y Or N");
}
/* Merge new R(eceive path) setting into other options */
/* "RY" = Use full filename exactly as received; don't use P option path
"RN" = Ignore received directory path if any; use path from P option */
if (p = find_option(buf,'R')) {
if (*p == 'Y' || *p == 'N') *sv->option_r = *p;
else ioerr(io,"Invalid R Flag Ignored; Should Be Y Or N");
}
/* Modify BPS Rate If We Have The BPS Rate Locked */
/* Limit this to 57.6k... The Amiga really can't safely go much faster... */
if (p = find_option(buf,'C')) {
len = atol(p);
if ((len < 300)||(len > 57600)) len = 0;
sprintf(sv->option_c,"%ld",len);
}
/* Figure out if we should be able to send no files like ZedZap */
if (p = find_option(buf,'N')) {
if (*p == 'Y' || *p == 'N') *sv->option_n = *p;
else ioerr(io,"Invalid N Flag Ignored; Should Be Y Or N");
}
/* Figure out the maximum block size that can be used... this must be */
/* below 8192 bytes */
if (p = find_option(buf,'M')) {
len = atol(p);
if (len == 0) len = 1024; /* default to regular zmodem block size */
if (len < MINBLOCK) len = MINBLOCK;
if (len > 8192) len = 8192;
sprintf(sv->option_m,"%ld",len);
}
/* Merge new Fallback/forward option into current settings if given */
/* "LY" = Allow fallback and fallforward for block length
"LN" = Never change the block length
"LB" = Only fall back
"LF" = Only fall forward (???) Should not do anything */
if (p = find_option(buf,'L')) {
if (*p == 'Y' || *p == 'N' || *p == 'B' || *p == 'F') *sv->option_l = *p;
else ioerr(io,"Invalid L Flag Ignored; Should Be Y, N, B, Or F");
}
/* Figure out if we can open the dos.library! While libraries are not*/
/* supposed to open it, we can do some pretty neat stuff if we do! */
if (p = find_option(buf,'U')) {
if (*p == 'Y' || *p == 'N') *sv->option_u = *p;
else ioerr(io,"Invalid U Flag Ignored; Should Be Y Or N");
}
/* Read the starting string for all environment (ENV:) variables that */
/* the protocol will use. This requires the dos.library to be open!!! */
if (p = find_option(buf,'V')) {
len = 0;
bufback = sv->option_v; /* backup the starting position */
while((*p != ',')&&(*p != 0)&&(len < 29)){
*bufback = *p; /* copy a byte */
p++; /* move up one */
bufback++; /* move up one */
*bufback = 0; /* clear the following byte */
len++;
}
}
/* Merge new P(ath) setting into other options */
/* "Pdir" = Receive files into directory "dir" if RN selected
"dir" can by any valid existing directory, with or without trailing "/" */
if (p = find_option(buf,'P')) {
strcpy(sv->option_p,p);
p = sv->option_p + strcspn(sv->option_p," ,\t\r\n");
*p = '\0';
}
Forbid(); /* no other program may change OPEN_LIBS now! */
OPEN_LIBS++;
if(*sv->option_u == 'Y'){
OpenDosLibrary();
}
Permit(); /* now its OK to change OPEN_LIBS */
return (*sv->option_a == 'Y') ? XPRS_SUCCESS|XPRS_NORECREQ|XPRS_HOSTMON : XPRS_SUCCESS|XPRS_NORECREQ;
}
/* Called by comm program to give us a chance to clean up before program ends */
long __saveds XProtocolCleanup(struct XPR_IO *io) {
Forbid(); /* make sure that no programs add to OPEN_LIBS so that we */
OPEN_LIBS--; /* can safely close the dos.library if it is open */
/* only the last program accessing the dos.library can safely close it */
/* without possibly crashing the system when other programs are trying */
/* to use dos.library functions */
if(!OPEN_LIBS) CloseDosLibrary(); /* no more programs are prossibly */
/* accessing the dos.library... at */
/* least we assume so */
Permit();
/* Release option memory, if any */
if (io->xpr_data) {
FreeMem(io->xpr_data,(long)sizeof(struct SetupVars));
io->xpr_data = NULL;
}
return XPRS_SUCCESS;
}
/* Called by comm program upon our request (XPRS_HOSTMON) to let us monitor
the incoming data stream for our receiver auto-activation string (ZRQINIT packet).
We only ask for this to be called if option AY is set. */
long __saveds XProtocolHostMon(struct XPR_IO *io,UBYTE *serbuff,long actual,long maxsize) {
static UBYTE startrcv[] = { ZPAD, ZDLE, ZHEX, "00" };
struct SetupVars *sv;
if (!(sv = (void *)io->xpr_data))
return actual; /* XProtocolSetup() never called?! */
if (!sv->matchptr)
sv->matchptr = startrcv;
/* Scan through serbuff to see if we can match all bytes in the start string in sequence */
for (sv->bufpos=serbuff; sv->bufpos < serbuff+actual; ++sv->bufpos) {
if (*sv->bufpos == *sv->matchptr) { /* if data matches current position in match string */
++sv->matchptr; /* increment match position */
if (!*sv->matchptr) { /* if at end of match string, it all matched */
sv->buflen = actual - (sv->bufpos - serbuff);
XProtocolReceive(io);
sv->matchptr = startrcv;
actual = 0;
break;
}
} else if (sv->matchptr > startrcv) { /* if mismatch, reset to start of match string */
sv->matchptr = startrcv;
if (*sv->bufpos == *sv->matchptr)
++sv->matchptr;
}
}
sv->bufpos = NULL;
return actual;
}
/* Called by comm program to let us monitor user's inputs; we never ask for
this to be called, but it's better to recover gracefully than guru the machine */
long __saveds XProtocolUserMon(struct XPR_IO *io,UBYTE *serbuff,long actual,long maxsize) {
return actual;
}
/* Perform setup and initializations common to both Send and Receive routines */
struct Vars *setup(struct XPR_IO *io) {
static long bauds[] = { 300,600,1200,2400,4800,7200,9600,12000,14400,16800,19200,31250,38400,57600,76800,115200 };
struct SetupVars *sv;
struct Vars *v;
long origbuf, newstatus;
#ifdef DEBUGLOG
long i, *lng;
#endif
/* Make sure comm program supports the required call-back functions */
if (!io->xpr_update) return NULL;
if (!io->xpr_fopen || !io->xpr_fclose || !io->xpr_fread || !io->xpr_fwrite ||
!io->xpr_fseek || !io->xpr_sread || !io->xpr_swrite) {
ioerr(io,"Comm Prog Missing Required Function(s); See Docs");
return NULL;
}
/* Hook in default transfer options if XProtocolSetup wasn't called */
if (!(sv = (void *)io->xpr_data)) {
io->xpr_data = AllocMem((long)sizeof(struct SetupVars),MEMF_CLEAR);
if (!(sv = (void *)io->xpr_data)) {
ioerr(io,"Not Enough Memory");
return NULL;
}
*sv = Default_Config;
}
/* Allocate memory for our unshared variables, to provide reentrancy */
if (!(v = AllocMem((long)sizeof(struct Vars),MEMF_CLEAR))) {
nomem:
ioerr(io,"Not Enough Memory");
return NULL;
}
v->Modemchar = v->Modembuf;
/* Allocate memory for our file I/O buffer; if we can't get as much as
requested, keep asking for less until we hit minimum before giving up */
v->Filebufmax = origbuf = atol(sv->option_b) * 1024;
while (!(v->Filebuf = AllocMem(v->Filebufmax,0L))) {
if (v->Filebufmax > 1024) v->Filebufmax -= 1024;
else {
FreeMem(v,(long)sizeof(struct Vars));
goto nomem;
}
}
/* maximum block size */
v->KSIZE = atol(sv->option_m);
/* new bps rate */
v->NEWBAUD = atol(sv->option_c);
/* send if there are no files */
if(*sv->option_n == 'Y'){v->USEZERO = TRUE;}
else{v->USEZERO = FALSE;}
/* open dos library */
if(*sv->option_u == 'Y'){v->use_dos_lib = 1;}
else{v->use_dos_lib = 0;}
/* fallback/forward */
if(*sv->option_l == 'Y'){v->fall_back = 1;v->fall_forward = 1;}
if(*sv->option_l == 'N'){v->fall_back = 0;v->fall_forward = 0;}
if(*sv->option_l == 'B'){v->fall_back = 1;v->fall_forward = 0;}
if(*sv->option_l == 'F'){v->fall_back = 0;v->fall_forward = 1;}
/* environment variable starter */
strcpy(v->env_starter,sv->option_v);
if((v->KSIZE * 2) > v->Filebufmax){
if(v->Filebufmax >= 1024) {v->KSIZE = 512 ;strcpy(sv->option_m,"512" );}
if(v->Filebufmax >= 2048) {v->KSIZE = 1024;strcpy(sv->option_m,"1024");}
if(v->Filebufmax >= 4096) {v->KSIZE = 2048;strcpy(sv->option_m,"2048");}
if(v->Filebufmax >= 8192) {v->KSIZE = 4096;strcpy(sv->option_m,"4096");}
if(v->Filebufmax >= 16384) {v->KSIZE = 8192;strcpy(sv->option_m,"8192");}
}
/* If framelength was intended to match buffer size, stay in sync */
v->Tframlen = atol(sv->option_f);
if (v->Tframlen && v->Tframlen == origbuf) v->Tframlen = v->Filebufmax;
v->ErrorLimit = atol(sv->option_e);
/* Copy caller's io struct into our Vars for easier passing */
v->io = *io;
#ifdef DEBUGLOG
if (!DebugLog) DebugLog = xpr_fopen(&v->io,DebugName,"w");
dlog(v,"XPR_IO struct:\n");
for (i=0,lng=(long *)io; i < sizeof(struct XPR_IO)/4; ++i) {
sprintf(v->Msgbuf," %08lx\n",*lng++);
dlog(v,v->Msgbuf);
}
#endif
/* Get baud rate; set serial port mode if necessary (and possible) */
if (v->io.xpr_setserial) {
v->Oldstatus = xpr_setserial(&v->io,-1L);
if (v->Oldstatus != -1) {
/* ZModem requires 8 data bits, no parity (full transparency),
leave other settings alone */
newstatus = v->Oldstatus & 0xFFFFE0BC;
/* newstatus |= on_flags; Here's where we'd turn bits on if we needed to */
if (newstatus != v->Oldstatus)
xpr_setserial(&v->io,newstatus);
v->Baud = bauds[(newstatus>>16) & 0xFF];
#ifdef DEBUGLOG
sprintf(v->Msgbuf,"Old Serial Status = %lx, New = %lx, Baud = %ld\n",v->Oldstatus,newstatus,v->Baud);
dlog(v,v->Msgbuf);
#endif
} else
v->Baud = 2400;
/* If no xpr_setserial(), muddle along with most likely guess */
} else v->Baud = 2400;
return v;
}
/* Set text/binary mode flags in accordance with T option setting */
void set_textmode(struct Vars *v) {
struct SetupVars *sv;
long i;
sv = (void *)v->io.xpr_data;
switch(*sv->option_t) {
case 'Y': /* Force text mode on receive; suggest text mode on send */
TY: v->Rxascii = TRUE;
v->Rxbinary = FALSE;
v->Lzconv = ZCNL;
break;
case 'N': /* Force binary mode on receive; suggest binary mode on send */
TN: v->Rxascii = FALSE;
v->Rxbinary = TRUE;
v->Lzconv = ZCBIN;
break;
case 'C': /* Ask comm program for proper mode for this file */
if (v->io.xpr_finfo) {
i = xpr_finfo(&v->io,v->Filename,2L);
if (i == 1) goto TN; /* Comm program says use binary mode */
if (i == 2) goto TY; /* Comm program says use text mode */
}
/* xpr_finfo() not provided (or failed); default to T? */
case '?':
v->Rxascii = v->Rxbinary = FALSE;
v->Lzconv = 0;
break;
}
}
/* Search for specified option setting in string */
UBYTE *find_option(UBYTE *buf,UBYTE option) {
while (*buf) {
buf += strspn(buf," ,\t\r\n");
if (*buf == option) return ++buf;
buf += strcspn(buf," ,\t\r\n");
}
return NULL;
}
/* send cancel string to get the other end to shut up */
void canit(struct Vars *v) {
static char canistr[] = { 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0 };
zmputs(v,canistr);
}
/* Send a string to the modem, with processing for \336 (sleep 1 sec)
and \335 (break signal, ignored since XPR spec doesn't support it) */
void zmputs(struct Vars *v,UBYTE *s) {
UBYTE c;
while (*s) {
switch (c = *s++) {
case '\336':
TimeOut(50L);
case '\335':
break;
default:
sendline(v,c);
}
}
sendbuf(v);
}
/* Write one character to the modem */
void xsendline(struct Vars *v,UBYTE c) {
v->Outbuf[v->Outbuflen++] = c;
if (v->Outbuflen >= sizeof(v->Outbuf))
sendbuf(v);
}
/* Send any data waiting in modem output buffer */
void sendbuf(struct Vars *v) {
if (v->Outbuflen) {
xpr_swrite(&v->io,v->Outbuf,(long)v->Outbuflen);
v->Outbuflen = 0;
}
}
/* Get a byte from the modem;
return TIMEOUT if no read within timeout tenths of a second,
return RCDO if carrier lost or other fatal error (sread returns -1).
Added in some buffering so we wouldn't hammer the system with single-byte
serial port reads. Also, the buffering makes char_avail() a lot easier to implement. */
short readock(struct Vars *v,short tenths) {
long t;
/* If there's data waiting in our buffer, return next byte */
if (v->Modemcount) {
gotdata:
--v->Modemcount;
return (short)(*v->Modemchar++);
}
/* Our buffer is empty; see if there's anything waiting in system buffer.
If the caller is in a hurry, don't wait around, but if it can spare
a half second, wait a bit and build up some input so we don't do as
many sread() calls. */
t = (tenths < 5) ? 0 : 500000;
#ifdef DEBUGLOG
sprintf(v->Msgbuf,"Input Buffer Empty; Calling sread For %ld Bytes, %ld usec\n",(long)sizeof(v->Modembuf),t);
dlog(v,v->Msgbuf);
#endif
v->Modemcount = xpr_sread(&v->io,v->Modembuf,(long)sizeof(v->Modembuf),t);
#ifdef DEBUGLOG
sprintf(v->Msgbuf," sread Returned %ld\n",v->Modemcount);
dlog(v,v->Msgbuf);
#endif
if (v->Modemcount < 0) { /* Carrier dropped or other fatal error; abort */
v->Modemcount = 0;
return RCDO;
} else if (!v->Modemcount) { /* Nothing in system buffer; try waiting */
t = tenths * 100000L - t;
#ifdef DEBUGLOG
sprintf(v->Msgbuf," Calling sread For 1 Byte, %ld usec\n",t);
dlog(v,v->Msgbuf);
#endif
v->Modemcount = xpr_sread(&v->io,v->Modembuf,1L,t);
#ifdef DEBUGLOG
sprintf(v->Msgbuf," sread Returned %ld\n",v->Modemcount);
dlog(v,v->Msgbuf);
#endif
if (v->Modemcount < 0) {
v->Modemcount = 0;
return RCDO;
} else if (!v->Modemcount) return TIMEOUT; /* Nothing received in time */
}
v->Modemchar = v->Modembuf; /* Reset buffer pointer to start of data */
goto gotdata;
}
/* Check if there's anything available to read from the modem */
char char_avail(struct Vars *v) {
if (v->Modemcount) return TRUE;
/* No data in our buffer; check system's input buffer */
v->Modemcount = xpr_sread(&v->io,v->Modembuf,(long)sizeof(v->Modembuf),0L);
if (v->Modemcount < 1) { /* Nothing in system buffer either */
v->Modemcount = 0;
return FALSE;
} else { /* System buffer had something waiting for us */
v->Modemchar = v->Modembuf;
return TRUE;
}
}
/* Update the elapsed time, expected total time, and effective data
transfer rate values for status display */
void update_rate(struct Vars *v) {
ULONG sent, elapsed, expect;
short hr, min;
struct timeval tv;
/* Compute effective data rate so far in characters per second */
sent = v->xpru.xpru_bytes - v->Strtpos;
GetSysTimeXPR(&tv);
elapsed = (tv.tv_secs & 0x7FFFFF) * 128 + tv.tv_micro / 8192;
elapsed -= (v->Starttime.tv_secs & 0x7FFFFF) * 128 + v->Starttime.tv_micro / 8192;
if (elapsed < 128) elapsed = 128;
/* If we haven't transferred anything yet (just starting), make reasonable
guess (95% throughput); otherwise, compute actual effective transfer rate */
if(v->NEWBAUD){
v->xpru.xpru_datarate = (sent) ? (sent * 128 / elapsed) : (v->NEWBAUD * 95 / 1000);
}
else{
v->xpru.xpru_datarate = (sent) ? (sent * 128 / elapsed) : (v->Baud * 95 / 1000);
}
/* Compute expected total transfer time based on data rate so far */
if (v->xpru.xpru_filesize < 0)
expect = 0; /* Don't know filesize; display time=0 */
else
expect = (v->xpru.xpru_filesize - v->Strtpos) / v->xpru.xpru_datarate;
hr = expect / 3600; /* How many whole hours */
expect -= hr * 3600; /* Remainder not counting hours */
min = expect / 60; /* How many whole minutes */
expect -= min * 60; /* Remaining seconds */
sprintf(v->Msgbuf,"%02ld:%02ld:%02ld",(long)hr,(long)min,expect);
v->xpru.xpru_expecttime = (char *)v->Msgbuf;
/* Compute elapsed time for this transfer so far */
elapsed /= 128;
hr = elapsed / 3600;
elapsed -= hr * 3600;
min = elapsed / 60;
elapsed -= min * 60;
sprintf(v->Msgbuf+20,"%02ld:%02ld:%02ld",(long)hr,(long)min,elapsed);
v->xpru.xpru_elapsedtime = (char *)v->Msgbuf+20;
}
/* Buffered file I/O fopen() interface routine */
void *bfopen(struct Vars *v,UBYTE *mode) {
if(v->File) bfclose(v); /* Why was the file still open? ARGH! */
/* Initialize file-handling variables */
v->Filebufpos = v->Filebuflen = v->Filebufcnt = 0;
v->Fileflush = FALSE;
v->Filebufptr = v->Filebuf;
/* Open the file */
#ifdef DEBUGLOG
sprintf(v->Msgbuf,"bfopen: %s %s\n",v->Filename,mode);
dlog(v,v->Msgbuf);
#endif
return (v->File = xpr_fopen(&v->io,v->Filename,mode));
}
/* Buffered file I/O fclose() interface routine */
void bfclose(struct Vars *v) {
if (v->File) {
/* If bfwrite() left data lingering in buffer, flush it out before closing */
if (v->Fileflush)
xpr_fwrite(&v->io,v->Filebuf,1L,v->Filebufcnt,v->File);
/* Close the file */
xpr_fclose(&v->io,v->File);
v->File = NULL;
}
}
/* Buffered file I/O fseek() interface routine */
void bfseek(struct Vars *v,long pos) {
long offset;
/* If new file position is within currently buffered section, reset pointers */
if (pos >= v->Filebufpos && pos < v->Filebufpos + v->Filebuflen) {
offset = pos - v->Filebufpos;
v->Filebufptr = v->Filebuf + offset;
v->Filebufcnt = v->Filebuflen - offset;
/* Otherwise, fseek() file and discard buffer contents to force new read */
} else {
xpr_fseek(&v->io,v->File,pos,0L);
v->Filebuflen = v->Filebufcnt = 0;
v->Filebufpos = pos;
}
}
/* Buffered file I/O fread() interface routine */
long bfread(struct Vars *v,UBYTE *buf,long length) {
long count, total = 0;
/* Keep going until entire request completed */
while (length > 0) {
/* Copy as much of the request as possible from the buffer */
count = (length <= v->Filebufcnt) ? length : v->Filebufcnt;
CopyMem(v->Filebufptr,buf,count);
#ifdef DEBUGLOG
sprintf(v->Msgbuf,"bfread Got %ld Bytes From Buffer\n",count);
dlog(v,v->Msgbuf);
#endif
buf += count;
total += count;
length -= count;
v->Filebufptr += count;
v->Filebufcnt -= count;
/* If we've emptied the buffer, read next buffer's worth */
if (!v->Filebufcnt) {
v->Filebufpos += v->Filebuflen;
v->Filebufptr = v->Filebuf;
v->Filebufcnt = v->Filebuflen = xpr_fread(&v->io,v->Filebuf,1L,v->Filebufmax,v->File);
#ifdef DEBUGLOG
sprintf(v->Msgbuf,"bfread Read %ld Bytes\n",v->Filebufcnt);
dlog(v,v->Msgbuf);
#endif
/* If we hit the EOF, return with however much we read so far */
if (!v->Filebufcnt) break;
}
}
return total;
}
/* Buffered file I/O fwrite() interface routine */
long bfwrite(struct Vars *v,UBYTE *buf,long length) {
long count, total = 0;
/* Keep going until entire request completed */
while (length > 0) {
/* Copy as much as will fit into the buffer */
count = v->Filebufmax - v->Filebufcnt;
if (length < count) count = length;
CopyMem(buf,v->Filebufptr,count);
#ifdef DEBUGLOG
sprintf(v->Msgbuf,"bfwrite Buffered %ld Bytes\n",count);
dlog(v,v->Msgbuf);
#endif
buf += count;
total += count;
length -= count;
v->Filebufptr += count;
v->Filebufcnt += count;
v->Fileflush = TRUE;
/* If we've filled the buffer, write it out */
if (v->Filebufcnt == v->Filebufmax) {
count = xpr_fwrite(&v->io,v->Filebuf,1L,v->Filebufcnt,v->File);
#ifdef DEBUGLOG
sprintf(v->Msgbuf,"bfwrite Wrote %ld Bytes\n",count);
dlog(v,v->Msgbuf);
#endif
if (count < v->Filebufcnt) return -1;
v->Filebufptr = v->Filebuf;
v->Filebufcnt = 0;
v->Fileflush = FALSE;
}
}
return total;
}
/* Have the comm program display an error message for us, using a
temporary XPR_UPDATE structure; used to display errors before Vars
gets allocated */
void ioerr(struct XPR_IO *io,char *msg) {
struct XPR_UPDATE xpru;
if (io->xpr_update) {
xpru.xpru_updatemask = XPRU_ERRORMSG;
xpru.xpru_errormsg = msg;
xpr_update(io,&xpru);
}
}
/* Have the comm program display an error message for us, using the
normal XPR_IO structure allocated in Vars */
void upderr(struct Vars *v,char *msg) {
v->xpru.xpru_updatemask = XPRU_ERRORMSG;
v->xpru.xpru_errormsg = msg;
if (msg == v->Msgbuf) /* Ensure message length < 50 */
msg[48] = '\0';
UpdateStats(v);
xpr_update(&v->io,&v->xpru);
#ifdef DEBUGLOG
dlog(v,msg);
dlog(v,"\n");
#endif
}
/* Have the comm program display a normal message for us */
void updmsg(struct Vars *v,char *msg) {
v->xpru.xpru_updatemask = XPRU_MSG;
v->xpru.xpru_msg = msg;
if (msg == v->Msgbuf) /* Ensure message length < 50 */
msg[48] = '\0';
UpdateStats(v);
xpr_update(&v->io,&v->xpru);
#ifdef DEBUGLOG
dlog(v,msg);
dlog(v,"\n");
#endif
}
/* Set the pass/fail status of this file */
void updstatus(struct Vars *v,char *filename,long status) {
v->xpru.xpru_updatemask = XPRU_FILENAME|XPRU_STATUS;
v->xpru.xpru_filename = filename;
v->xpru.xpru_status = status;
UpdateStats(v);
xpr_update(&v->io,&v->xpru);
}
/* Figure out how many bytes are free on the drive we're uploading to.
Stubbed out for now; not supported by XPR spec. */
long getfree(void) {
return 0x7FFFFFFF;
}
/* Check whether file already exists; used to detect potential overwrites */
char exist(struct Vars *v) {
void *file;
file = xpr_fopen(&v->io,v->Filename,"r");
if (file) {
xpr_fclose(&v->io,file);
return TRUE;
} else return FALSE;
}
#ifdef DEBUGLOG
/* Write a message to the debug log */
void dlog(struct Vars *v,UBYTE *s) {
/* Open the debug log if it isn't already open */
if (!DebugLog) DebugLog = xpr_fopen(&v->io,DebugName,"a");
xpr_fwrite(&v->io,s,1L,(long)strlen(s),DebugLog);
/* Close file to flush output buffer; comment these two lines out if
you aren't crashing your system and don't mind waiting until the
transfer finishes to look at your log file.
xpr_fclose(&v->io,DebugLog);
DebugLog = NULL; */
}
#endif